package org.dalmatian.common.redis.manager;

import cn.hutool.core.collection.CollectionUtil;
import org.dalmatian.common.core.domain.R;
import org.dalmatian.common.core.utils.SolonUtils;
import org.dalmatian.common.redis.cache.Cache;
import java.util.Collection;
import java.util.concurrent.Callable;
import lombok.extern.slf4j.Slf4j;


/**
 * Cache 装饰器模式(用于扩展 Caffeine 一级缓存)
 *
 * @author LionLi
 */
@Slf4j
public class CaffeineCacheDecorator implements Cache {

    private static final com.github.benmanes.caffeine.cache.Cache<Object, Object>
        CAFFEINE = SolonUtils.getBean(com.github.benmanes.caffeine.cache.Cache.class);

    private final Cache cache;

    private final String name;

    public CaffeineCacheDecorator(Cache cache, String name) {
        this.cache = cache;
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public Object getNativeCache() {
        return cache.getNativeCache();
    }

    public String getUniqueKey(Object key) {
        return name + ":" + key;
    }


    @Override
    public Object get(Object key) {
        try {
            Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key));
            boolean shouldInvalidate = false;
            if (o instanceof R<?> r) {
                if (!R.isSuccess(r)) {
                    shouldInvalidate = true;
                } else if (r.getData() == null) {
                    shouldInvalidate = true;
                } else if (r.getData() instanceof Collection k) {
                    if (CollectionUtil.isEmpty(k)) {
                        shouldInvalidate = true;
                    }
                }
            }
            if (shouldInvalidate) {
                evict(key);
                return null;
            }
            return o;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("CaffeineCacheDecorator error", e);
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(Object key, Class<T> type) {
        Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, type));
        return (T) o;
    }

    @Override
    public void put(Object key, Object value) {
        boolean shouldInvalidate = true;
        if (value instanceof R<?> r) {
            if (!R.isSuccess(r)) {
                shouldInvalidate = false;
            }
        }
        // 如果value是R类型且成功，则只更新缓存，不失效
        if (shouldInvalidate) {
            // 其他情况，先失效旧的缓存项，再更新缓存
            CAFFEINE.invalidate(getUniqueKey(key));
            cache.put(key, value);
        }
    }

    @Override
    public Object putIfAbsent(Object key, Object value) {
        boolean shouldInvalidate = true;
        if (value instanceof R<?> r) {
            if (!R.isSuccess(r)) {
                shouldInvalidate = false;
            }
        }
        // 如果value是R类型且成功，则只更新缓存，不失效
        if (shouldInvalidate) {
            // 其他情况，先失效旧的缓存项，再更新缓存
            CAFFEINE.invalidate(getUniqueKey(key));
            return cache.putIfAbsent(key, value);
        }
        return null;
    }

    @Override
    public void evict(Object key) {
        evictIfPresent(key);
    }

    @Override
    public boolean evictIfPresent(Object key) {
        boolean b = cache.evictIfPresent(key);
        if (b) {
            CAFFEINE.invalidate(getUniqueKey(key));
        }
        return b;
    }

    @Override
    public void clear() {
        cache.clear();
    }

    @Override
    public boolean invalidate() {
        return cache.invalidate();
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, valueLoader));
        return (T) o;
    }

}
